package com.handinfo.android.core.object;

import java.io.DataInputStream;
import java.io.IOException;

import com.handinfo.android.DWGameManager;
import com.handinfo.android.core.graphics.DWBitmap;
import com.handinfo.android.core.graphics.DWGraphics;
import com.handinfo.android.core.resource.DWSerializable;
import com.handinfo.android.core.resource.DWSerializableFactory;
import com.handinfo.android.core.resource.ResHead;
import com.handinfo.android.core.resource.Resource;
import com.handinfo.android.core.resource.ResourceManager;

public class Animation extends DWSerializable
{
	private DWBitmap[] m_bitmaps;

	/**
	 * 帧数据 1维长度=帧数; 2维长度=该帧的模块数 * 4 每个模块4个属性，分别为模块索引、翻转标识、X坐标、Y坐标
	 */
	private short[][] m_frames;

	/** 是否有帧碰撞信息 */
	public boolean m_hasFrameCollide;

	/**
	 * 帧碰撞数据 1维长度=帧数； 2维长度=碰撞框信息
	 */
	public short[][] m_framesCollideBox;
	short[][] m_framesActiveBox;

	/**
	 * 动作数据 1维长度=动作数; 2维长度=该动作的帧数 每帧1个short值存储数据，但分为两个属性，分别为帧索引、该帧持续帧数
	 * short的前6位是持续帧数，后10位为帧索引
	 */
	public short[][] m_actions;

	public static final int MODULE_PROP_COUNT = 5;
	public static final int MODULE_PROP_IMG = 0;
	public static final int MODULE_PROP_X = 1;
	public static final int MODULE_PROP_Y = 2;
	public static final int MODULE_PROP_W = 3;
	public static final int MODULE_PROP_H = 4;

	/**
	 * 所有module的集合 1维=module数; 2维=module信息(一共5个short)
	 */
	private short[][] m_modules;

	/**
	 * 载入module数据
	 * 
	 * @param dis
	 * @throws java.lang.Exception
	 */
	public void loadModule(DataInputStream dis) throws IOException
	{
		int count = dis.readShort(); // 模块数量

		m_modules = new short[count][MODULE_PROP_COUNT];
		for (int i = 0; i < count; i++) {
			m_modules[i][0] = dis.readShort();
			m_modules[i][1] = dis.readShort();
			m_modules[i][2] = dis.readShort();
			m_modules[i][3] = dis.readShort();
			m_modules[i][4] = dis.readShort();
		}
	}

	/**
	 * 载入帧数据
	 * 
	 * @param dis
	 * @throws java.lang.Exception
	 */
	public void loadFrame(DataInputStream dis) throws IOException
	{
		int count = dis.readShort(); // 帧数量
		m_frames = new short[count][];
		m_hasFrameCollide = (dis.readByte() != 0);
		if (m_hasFrameCollide) {
			m_framesCollideBox = new short[count][];
			m_framesActiveBox = new short[count][];
		}
		int count2;
		for (int i = 0; i < count; i++) {
			count2 = dis.readUnsignedByte(); // 该帧的模块数
			m_frames[i] = new short[count2 * 4];
			for (int ii = 0; ii < count2 * 4; ii += 4) {
				m_frames[i][ii] = (short) dis.readUnsignedShort();
				m_frames[i][ii + 1] = (short) dis.readUnsignedShort();
				m_frames[i][ii + 2] = (short) dis.readUnsignedShort();
				m_frames[i][ii + 3] = (short) dis.readUnsignedShort();
			}
			if (m_hasFrameCollide) {
				m_framesCollideBox[i] = new short[4];
				m_framesActiveBox[i] = new short[4];
				m_framesCollideBox[i][0] = dis.readShort();
				m_framesCollideBox[i][1] = dis.readShort();
				m_framesCollideBox[i][2] = dis.readShort();
				m_framesCollideBox[i][3] = dis.readShort();
				m_framesActiveBox[i][0] = dis.readShort();
				m_framesActiveBox[i][1] = dis.readShort();
				m_framesActiveBox[i][2] = dis.readShort();
				m_framesActiveBox[i][3] = dis.readShort();
			}
		}
	}

	/**
	 * 载入动作数据
	 * 
	 * @param dis
	 * @throws java.lang.Exception
	 */
	public void loadAction(DataInputStream dis) throws IOException
	{
		int count = dis.readShort(); // 动作数量
		m_actions = new short[count][];
		int data1;
		int data2;
		int count2;
		for (int i = 0; i < count; i++) {
			count2 = dis.readUnsignedByte(); // 该动作的帧数
			m_actions[i] = new short[count2];
			for (int j = 0; j < count2; j++) {
				// 这两个byte总共加起来16位，其中的十位用于记录帧索引，另外的6位记录帧持续时间
				data1 = dis.readUnsignedByte();
				data2 = dis.readUnsignedByte();
				m_actions[i][j] = (short) ((data2 << 8) + data1);
			}
		}
	}

	/**
	 * 载入图片
	 * 
	 * @param res
	 */
	public void loadBitamp(Resource res)
	{
		m_bitmaps = new DWBitmap[m_refsResHead.length];
		for (int i = 0; i < m_refsResHead.length; i++) {
			m_bitmaps[i] = (DWBitmap) (ResourceManager.getInstance()
					.loadResource(res, m_refsResHead[i]));
		}
	}

	/**
	 * 绘制
	 * 
	 * @param g
	 * @param x
	 * @param y
	 * @param flipX
	 * @param flipY
	 * @param frameIndex
	 */
	public void draw(DWGraphics g, int x, int y, boolean flipX, boolean flipY,
			int frameIndex)
	{
		if (!m_loadFinished)
			return;
		if (m_frames == null || m_modules == null)
			return;
		short[] frame = null;
		frame = m_frames[frameIndex];
		int imgId;
		int modID, flag, posX, posY;
		short modX, modY, modW, modH;
		boolean flipX_real, flipY_real;
		for (int i = 0; i < frame.length; i += 4) {
			modID = (frame[i] & 0xFFFF);
			flag = frame[i + 1] & 0xFFFF;

			imgId = m_modules[modID][MODULE_PROP_IMG];
			modX = m_modules[modID][MODULE_PROP_X];
			modY = m_modules[modID][MODULE_PROP_Y];
			modW = m_modules[modID][MODULE_PROP_W];
			modH = m_modules[modID][MODULE_PROP_H];

			if (modX + modW > m_bitmaps[imgId].getWidth()) {
				modW = (short) (m_bitmaps[imgId].getWidth() - modX);
			}
			if (modY + modH > m_bitmaps[imgId].getHeight()) {
				modH = (short) (m_bitmaps[imgId].getHeight() - modY);
			}
			if (modW <= 0 || modH <= 0) {
				continue;
			}

			flipX_real = flipX ^ ((flag & 0x01) != 0);
			flipY_real = flipY ^ ((flag & 0x02) != 0);

			if (flipX_real) {
				flag |= 0x01;
			}
			else {
				flag &= 0xfffffffe;
			}
			if (flipY_real) {
				flag |= 0x02;
			}
			else {
				flag &= 0xfffffffd;
			}

			posX = x;
			posY = y;
			int clipW = modW, clipH = modH;
			switch (flag) {
				case 1:
					posX -= modW;
					break;
				case 2:
					posY -= modH;
					break;
				case 3:
					posX -= modW;
					posY -= modH;
					break;
				case 4:
					posX -= modH;
					clipW = modH;
					clipH = modW;
					break;
				case 5:
					clipW = modH;
					clipH = modW;
					break;
				case 6:
					posX -= modH;
					posY -= modW;
					clipW = modH;
					clipH = modW;
					break;
				case 7:
					posY -= modW;
					clipW = modH;
					clipH = modW;
					break;
				default:
					break;
			}

			flag = DWGraphics.trans(flag);

			if (flipX) {
				posX -= frame[i + 2];
			}
			else {
				posX += frame[i + 2];
			}
			if (flipY) {
				posY -= frame[i + 3];
			}
			else {
				posY += frame[i + 3];
			}

			if (posX + modW < 0 || posX >= DWGameManager.Screen_Width) {
				continue;
			}
			if (posY + modH < 0 || posY >= DWGameManager.Screen_Height) {
				continue;
			}

			g.setClip(posX, posY, clipW, clipH);
			if (flag == 0) {
				g.drawBitmap(m_bitmaps[imgId].getImage(), posX - modX, posY - modY,
						DWGraphics.LEFT | DWGraphics.TOP);

			}
			else {
				g.drawRegion(m_bitmaps[imgId].getImage(), modX,
						modY, modW, modH, flag, posX, posY, 0);
			}
		}
	}
	
	/**
	 * 绘制
	 * 
	 * @param g
	 * @param x
	 * @param y
	 * @param flipX
	 * @param flipY
	 * @param frameIndex
	 */
	public void draw(DWGraphics g, int x, int y, boolean flipX, boolean flipY,
			int frameIndex, float scaleX, float scaleY)
	{
		if (!m_loadFinished)
			return;
		if (m_frames == null || m_modules == null)
			return;
		short[] frame = null;
		frame = m_frames[frameIndex];
		int imgId;
		int modID, flag, posX, posY;
		short modX, modY, modW, modH;
		boolean flipX_real, flipY_real;
		for (int i = 0; i < frame.length; i += 4) {
			modID = (frame[i] & 0xFFFF);
			flag = frame[i + 1] & 0xFFFF;

			imgId = m_modules[modID][MODULE_PROP_IMG];
			modX = m_modules[modID][MODULE_PROP_X];
			modY = m_modules[modID][MODULE_PROP_Y];
			modW = m_modules[modID][MODULE_PROP_W];
			modH = m_modules[modID][MODULE_PROP_H];

			if (modX + modW > m_bitmaps[imgId].getWidth()) {
				modW = (short) (m_bitmaps[imgId].getWidth() - modX);
			}
			if (modY + modH > m_bitmaps[imgId].getHeight()) {
				modH = (short) (m_bitmaps[imgId].getHeight() - modY);
			}
			if (modW <= 0 || modH <= 0) {
				continue;
			}

			flipX_real = flipX ^ ((flag & 0x01) != 0);
			flipY_real = flipY ^ ((flag & 0x02) != 0);

			if (flipX_real) {
				flag |= 0x01;
			}
			else {
				flag &= 0xfffffffe;
			}
			if (flipY_real) {
				flag |= 0x02;
			}
			else {
				flag &= 0xfffffffd;
			}

			posX = x;
			posY = y;
			int clipW = modW, clipH = modH;
			switch (flag) {
				case 1:
					posX -= modW;
					break;
				case 2:
					posY -= modH;
					break;
				case 3:
					posX -= modW;
					posY -= modH;
					break;
				case 4:
					posX -= modH;
					clipW = modH;
					clipH = modW;
					break;
				case 5:
					clipW = modH;
					clipH = modW;
					break;
				case 6:
					posX -= modH;
					posY -= modW;
					clipW = modH;
					clipH = modW;
					break;
				case 7:
					posY -= modW;
					clipW = modH;
					clipH = modW;
					break;
				default:
					break;
			}

			flag = DWGraphics.trans(flag);

			if (flipX) {
				posX -= frame[i + 2];
			}
			else {
				posX += frame[i + 2];
			}
			if (flipY) {
				posY -= frame[i + 3];
			}
			else {
				posY += frame[i + 3];
			}

			if (posX + modW < 0) {
				continue;
			}
			if (posY + modH < 0) {
				continue;
			}

			g.drawRegion(m_bitmaps[imgId].getImage(), modX,
					modY, modW, modH, flag, posX * scaleX, posY * scaleY, modW * scaleX, modH * scaleY, DWGraphics.LEFT
							| DWGraphics.TOP);
		}
	}

	@Override
	public void read(Resource res, DataInputStream dis) throws IOException
	{
		readHead(res, dis);
		// 载入模块数据
		loadModule(dis);
		// 载入所有帧数据
		loadFrame(dis);
		// 载入所有动作数据
		loadAction(dis);
		// 载入图片
		loadBitamp(res);

		checkLoadFinished();
	}

	@Override
	public void updateComponent(ResHead head, DWSerializable component)
	{
		if (m_loadFinished)
			return;
		if (head.m_type != DWSerializableFactory.RESOURCE_TYPE_PNG)
			return;
		if (m_refsResHead == null || m_refsResHead.length == 0)
			return;
		for (int i = 0; i < m_refsResHead.length; i++) {
			if (m_refsResHead[i].equals(head)) {
				m_bitmaps[i] = (DWBitmap) component;
				checkLoadFinished();
			}
		}
	}

	@Override
	public void checkLoadFinished()
	{
		if (m_bitmaps == null) {
			m_loadFinished = false;
			return;
		}
		for (int i = 0; i < m_bitmaps.length; i++) {
			if (m_bitmaps[i] == null) {
				m_loadFinished = false;
				return;
			}
		}
		m_loadFinished = true;
	}

	@Override
	public boolean isContainRefHead(ResHead head)
	{
		if (head.m_type != DWSerializableFactory.RESOURCE_TYPE_PNG)
			return false;
		return super.isContainRefHead(head);
	}

	@Override
	public void dispose()
	{
		disposeHead();
		if (m_frames != null) {
			for (int i = 0; i < m_frames.length; i++) {
				m_frames[i] = null;
			}
			m_frames = null;
		}
		if (m_actions != null) {
			for (int i = 0; i < m_actions.length; i++) {
				m_actions[i] = null;
			}
			m_actions = null;
		}
		if (m_modules != null) {
			for (int i = 0; i < m_modules.length; i++) {
				m_modules[i] = null;
			}
			m_modules = null;
		}
		if (m_bitmaps != null) {
			for (int i = 0; i < m_bitmaps.length; i++) {
				m_bitmaps[i] = null;
			}
			m_bitmaps = null;
		}
	}

	/**
	 * 销毁该Animation，包括其对应的图片
	 */
	public void destroy()
	{
		disposeHead();
		if (m_frames != null) {
			for (int i = 0; i < m_frames.length; i++) {
				m_frames[i] = null;
			}
			m_frames = null;
		}
		if (m_actions != null) {
			for (int i = 0; i < m_actions.length; i++) {
				m_actions[i] = null;
			}
			m_actions = null;
		}
		if (m_modules != null) {
			for (int i = 0; i < m_modules.length; i++) {
				m_modules[i] = null;
			}
			m_modules = null;
		}
		if (m_bitmaps != null) {
			for (int i = 0; i < m_bitmaps.length; i++) {
				if (m_bitmaps[i] != null) {
					// 从res中移除依赖的图片
					if (!m_resource.isUseing(this,m_bitmaps[i].m_resHead)) {
						m_resource.remove(m_bitmaps[i].m_resHead);
					}
					m_bitmaps[i] = null;
				}
			}
			m_bitmaps = null;
		}
	}

}
